import Vue from "vue";
import store from "../store";
import VueRouter from "vue-router";
import NProgress from "nprogress";
import "nprogress/nprogress.css";
import { Session } from "@/utils/storage";
import { PrevLoading } from "@/utils/loading.js";
import { getMenuAdmin, getMenuTest } from "@/api/menu";

// 解决 `element ui` 导航栏重复点菜单报错问题
const originalPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location) {
  return originalPush.call(this, location).catch((err) => err);
};

// 安装 VueRouter 插件
Vue.use(VueRouter);

// 定义动态路由
const dynamicRoutes = [
  {
    path: "/",
    name: "/",
    component: "layout/index",
    redirect: "/home",
    meta: {
      isKeepAlive: true,
    },
    children: [],
  },
];

// 定义静态路由
const staticRoutes = [
  {
    path: "/login",
    name: "login",
    component: () => import("@/views/login"),
    meta: {
      title: "登录",
    },
  },
  {
    path: "/404",
    name: "notFound",
    component: () => import("@/views/error/404.vue"),
    meta: {
      title: "message.staticRoutes.notFound",
    },
  },
  {
    path: "/401",
    name: "noPower",
    component: () => import("@/views/error/401.vue"),
    meta: {
      title: "message.staticRoutes.noPower",
    },
  },
];

// 加载静态路由
const createRouter = () =>
  new VueRouter({
    routes: staticRoutes,
  });

// 创建路由
const router = createRouter();

// 加载 loading
PrevLoading.start();

// 多级嵌套数组处理成一维数组
export function formatFlatteningRoutes(arr) {
  if (arr.length <= 0) return false;
  for (let i = 0; i < arr.length; i++) {
    if (arr[i].children) {
      arr = arr.slice(0, i + 1).concat(arr[i].children, arr.slice(i + 1));
    }
  }
  return arr;
}

// 处理 tagsViewList 数据，默认路由全部缓存
// isKeepAlive 处理 `name` 值，进行路由缓存
export function formatTwoStageRoutes(arr) {
  if (arr.length <= 0) return false;
  const newArr = [];
  const cacheList = [];
  arr.forEach((v) => {
    newArr.push({ ...v });
    cacheList.push(v.name);
    store.dispatch("keepAliveNames/setCacheKeepAlive", cacheList);
  });
  return newArr;
}

// 判断路由 meta.roles 中是否包含当前登录用户权限字段
export function hasAuth(roles, route) {
  if (route.meta && route.meta.roles)
    return roles.some((role) => route.meta.roles.includes(role));
  else return true;
}

// 递归过滤有权限的路由
export function setFilterMenuFun(routes, role) {
  const menu = [];
  routes.forEach((route) => {
    const item = { ...route };
    if (hasAuth(role, item)) {
      if (item.children) item.children = setFilterMenuFun(item.children, role);
      menu.push(item);
    }
  });
  return menu;
}

// 缓存多级嵌套数组处理后的一维数组(tagsView、菜单搜索中使用：未过滤隐藏的(isHide))
export function setCacheTagsViewRoutes(arr) {
  // 先处理有权限的路由，否则 tagsView、菜单搜索中无权限的路由也将显示
  const rolesRoutes = setFilterMenuFun(
    arr,
    store.state.userInfos.userInfos.roles
  );
  // 添加到 vuex setTagsViewRoutes 中
  store.dispatch(
    "tagsViewRoutes/setTagsViewRoutes",
    formatTwoStageRoutes(formatFlatteningRoutes(rolesRoutes))
  );
}

// 递归处理多余的 layout : <router-view>，让需要访问的组件保持在第一层 layout 层。
// 因为 `keep-alive` 只能缓存二级路由
// 默认初始化时就执行
export function keepAliveSplice(to) {
  if (to.matched && to.matched.length > 2) {
    to.matched.map((v, k) => {
      if (v.components.default instanceof Function) {
        v.components.default().then((components) => {
          if (components.default.name === "parent") {
            to.matched.splice(k, 1);
            router.push({ path: to.path, query: to.query });
            keepAliveSplice(to);
          }
        });
      } else {
        if (v.components.default.name === "parent") {
          to.matched.splice(k, 1);
          keepAliveSplice(to);
        }
      }
    });
  }
}

// 处理后端返回的 `component` 路径，拼装实现懒加载
export function loadView(path) {
  if (path.indexOf("layout") > -1)
    return () => Promise.resolve(require(`@/${path}`));
  else return () => Promise.resolve(require(`@/views/${path}`));
}

// 递归处理每一项 `component` 中的路径
export function dynamicRouter(routes) {
  return routes.map((view) => {
    if (view.component) view.component = loadView(view.component);
    if (view.children) dynamicRouter(view.children);
    return view;
  });
}

// 添加路由，模拟数据与方法，可自行进行修改 admin
// 添加动态路由，`{ path: '*', redirect: '/404' }` 防止页面刷新，静态路由丢失问题
// next({ ...to, replace: true }) 动态路由 addRoute 完毕后才放行，防止刷新时 NProgress 进度条加载2次
// 文档地址：https://router.vuejs.org/zh/api/#router-addroutes
export function adminUser(router, to, next) {
  resetRouter();
  getMenuAdmin()
    .then(async (res) => {
      // 读取用户信息，获取对应权限进行判断
      store.dispatch("userInfos/setUserInfos");
      store.dispatch(
        "routesList/setRoutesList",
        setFilterMenuFun(res.data, store.state.userInfos.userInfos.roles)
      );
      dynamicRoutes[0].children = res.data;
      const awaitRoute = await dynamicRouter(dynamicRoutes);
      [...awaitRoute, { path: "*", redirect: "/404" }].forEach((route) => {
        router.addRoute({ ...route });
      });
      setCacheTagsViewRoutes(JSON.parse(JSON.stringify(res.data)));
      next({ ...to, replace: true });
    })
    .catch(() => {});
}

// 添加路由，模拟数据与方法，可自行进行修改 test
// 添加动态路由，`{ path: '*', redirect: '/404' }` 防止页面刷新，静态路由丢失问题
export function testUser(router, to, next) {
  resetRouter();
  getMenuTest()
    .then(async (res) => {
      // 读取用户信息，获取对应权限进行判断
      store.dispatch("userInfos/setUserInfos");
      store.dispatch(
        "routesList/setRoutesList",
        setFilterMenuFun(res.data, store.state.userInfos.userInfos.roles)
      );
      dynamicRoutes[0].children = res.data;
      const awaitRoute = await dynamicRouter(dynamicRoutes);
      [...awaitRoute, { path: "*", redirect: "/404" }].forEach((route) => {
        router.addRoute({ ...route });
      });
      setCacheTagsViewRoutes(JSON.parse(JSON.stringify(res.data)));
      next({ ...to, replace: true });
    })
    .catch(() => {});
}

// 重置路由
export function resetRouter() {
  router.matcher = createRouter().matcher;
}

// 延迟关闭进度条
export function delayNProgressDone(time = 300) {
  setTimeout(() => {
    NProgress.done();
  }, time);
}

// 动态加载后端返回路由路由(模拟数据)
export function getRouterList(router, to, next) {
  if (!Session.get("userInfo")) return false;
  if (Session.get("userInfo").userName === "admin") adminUser(router, to, next);
  else if (Session.get("userInfo").userName === "test")
    testUser(router, to, next);
}

// 路由加载前
router.beforeEach((to, from, next) => {
  keepAliveSplice(to);
  NProgress.configure({ showSpinner: false });
  if (to.meta.title && to.path !== "/login") NProgress.start();
  const token = Session.get("token");
  if (to.path === "/login" && !token) {
    NProgress.start();
    next();
    delayNProgressDone();
  } else {
    if (!token) {
      NProgress.start();
      next("/login");
      Session.clear();
      delayNProgressDone();
    } else if (token && to.path === "/login") {
      next("/home");
      delayNProgressDone();
    } else {
      if (Object.keys(store.state.routesList.routesList).length <= 0) {
        getRouterList(router, to, next);
      } else {
        next();
        delayNProgressDone(0);
      }
    }
  }
});

// 路由加载后
router.afterEach(() => {
  PrevLoading.done();
  delayNProgressDone();
});

// 导出路由
export default router;
